package com.example.demojimmer.domain.userauth.filter;

import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTValidator;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.example.demojimmer.config.JwtConfig;
import com.example.demojimmer.config.SecurityConfig;
import com.example.demojimmer.domain.userauth.exception.JwtException4010;
import com.example.demojimmer.domain.userauth.exception.JwtException4011;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        log.debug("JwtAuthenticationFilter认证开始>>>>>>>");
        log.debug("JwtConfig.headerkeyName>>>{}", JwtConfig.headerkeyName);
        String jwtToken = request.getHeader(JwtConfig.headerkeyName);

        // 如果token为空，则放行，继续处理下一个过滤器
        if (StrUtil.isBlankOrUndefined(jwtToken)) {
            filterChain.doFilter(request, response);
            return;
        }

        //如果token有值  解析

        JWT jwt = null;
        try {
            jwt = JWTUtil.parseToken(jwtToken);
        } catch (Exception e) {
            //token解析失败
            throw new JwtException4010(e.getMessage());
        }

        //验签
        JWTValidator jwtValidator = JWTValidator.of(jwt);
        RSA rsa = new RSA(null, JwtConfig.publicKey);
        JWTSigner jwtSigner = JWTSignerUtil.rs256(rsa.getPublicKey());
        try {
            jwtValidator.validateAlgorithm(jwtSigner);
        } catch (Exception e) {
            e.printStackTrace();
            throw new JwtException4010(e.getMessage());
        }

        try {
            //验时间
            jwtValidator.validateDate();
        } catch (ValidateException e) {
            //时间校验不过
            throw new JwtException4011(e.getMessage());
        }

        //扩展其他  安全校验
        //刷新token接口的
        if ((!"/refreshToken".equals(request.getRequestURI())) && (!"TokenS".equals(jwt.getPayload("tokenName")))) {
            //非刷新的接口  验证是短token
            throw new InsufficientAuthenticationException("token认证失败");
        }

        if (("/refreshToken".equals(request.getRequestURI())) && (!"TokenL".equals(jwt.getPayload("tokenName")))) {
            //刷新的接口  验证是长token
            throw new InsufficientAuthenticationException("token认证失败");
        }

        //成功验证 放入上下文
        String subject = (String) jwt.getPayload(JWTPayload.SUBJECT);
        SecurityConfig.User user = JSONUtil.toBean(subject, SecurityConfig.User.class);
        //使用UsernamePasswordAuthenticationToken.authenticated构建已认证的UsernamePasswordAuthenticationToken
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(
                user, //jwt认证成功的 UserDetails
                user.getPassword(),
                user.getAuthorities() //权限
        );
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

        //过
        filterChain.doFilter(request, response);
    }
}
